/**
 * @file    app_user.c
 * @author  Azolla (1228449928@qq.com)
 * @brief
 * @version 0.1
 * @date    2022-09-19
 * 
 * @copyright Copyright (c) 2022
 * */
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/event_groups.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "esp_system.h"
#include "mbedtls/base64.h"

#include "ble_gap.h"
#include "ble_mesh_prov.h"
#include "ble_gatts.h"
#include "ble_gattc.h"
#include "ble_bind.h"

#include "wifi_init.h"
#include "wifi_sock.h"
#include "wifi_sntp.h"
#include "wifi_user.h"
#include "wifi_ota.h"
#include "wifi_mqtt.h"

#include "hal_rs485.h"
#include "hal_a7106.h"
#include "audio_board_init.h"
 
#include "app_user.h"
#include "app_scene.h"

#define CONFIG_RS485RF_ENABLE   0   // 1: 使能485转RF控制  
 
#define TAG  "app_user"

/* 百度账号
 * 13860115663
 * yirui1234
 * */

#ifdef TAG
#define APP_USER_LOGI(format, ...)    ESP_LOGI(TAG, format, ##__VA_ARGS__)
#define APP_USER_LOGW(format, ...)    ESP_LOGW(TAG, format, ##__VA_ARGS__)
#define APP_USER_LOGE(format, ...)    ESP_LOGE(TAG, format, ##__VA_ARGS__)
#else
#define APP_USER_LOGI(format, ...)
#define APP_USER_LOGW(format, ...)
#define APP_USER_LOGE(format, ...)
#endif

//==============================================================================================================
//==============================================================================================================
 
typedef struct {

    bool sys_reset;        // 1: 软件复位
    uint8_t stop;
    struct {
        a7106_id_t id;
		uint8_t  match;	  // 对码
        uint8_t  channel;
        uint8_t  inter;   // 接收中断信号
        uint8_t  buff[4]; // 发送buff
        uint8_t  reissue; // 补发次数
    } rf;
 
} app_run_t;
static app_run_t app = { 0 };

typedef struct {
    a7106_id_t rfid;
    uint8_t addr;    // RS485地址
    uint8_t update;  // 1: 有更新
} nvs_user_t;
static nvs_user_t nvs_user;
 
esp_err_t nvs_user_handle(nvs_user_t *nvs, nvs_open_mode_t nvs_open_mode)
{
    return nvs_blob_handle((nvs_user_t *)nvs, sizeof(nvs_user_t), "user_key", nvs_open_mode);
}
 
//==============================================================================================================
//==============================================================================================================
 
void rf_motor_write(const uint8_t *data, uint8_t reissue)
{
    app.rf.reissue = reissue;
    if (data[0]) {
        memcpy(app.rf.buff, data, 4);
    }
//a7106_write_data(data, 4);  // RX -> STANDBY -> TX
}

static void app_a7106_handler(void)
{
	if (app.rf.match) app.rf.match--;  // 对码倒计时
    if (!gpio_get_level(3) || app.rf.match) {  // 按住RF对码键
        if (app.rf.id.u32 != A7105_ID_CFIG) {
            app.rf.id.u32  = A7105_ID_CFIG;
            app.rf.channel = A7105_CH_CFIG;
            a7106_write_id(app.rf.id);
            a7106_set_channel(app.rf.channel);
            a7106_write_strobe(A7105_STROBE_RX); 
            APP_USER_LOGI("A7105_STROBE_RX");
        } else if (app.rf.inter) {  // 有接收中断信号！
            app.rf.inter = 0;
            a7106_id_t id;
            a7106_read_data(id.u8, 4);  // 读数据
            esp_log_buffer_hex("RX", id.u8, 4);
            if (nvs_user.rfid.u32 != id.u32) {
                nvs_user.rfid.u32 = id.u32;
                nvs_user.update = true;
            }
			app.rf.match = 0;
			rf_motor_write((const uint8_t[]){{0x55,0x55,0xdd,0xdd}}, 2);  // 对码成功后，控制器会响两声
            static bool led_blank = 0;
            led_blank = !led_blank;
            gpio_set_level(GPIO_NUM_37, led_blank);
        }
        return;
    } else if (app.rf.id.u32 != nvs_user.rfid.u32) {
        app.rf.id.u32  = nvs_user.rfid.u32;
        app.rf.channel = app.rf.id.u8[1];  // 通道值 = ID[1]
		if (app.rf.channel % 2) app.rf.channel += 1;
        a7106_write_id(app.rf.id);
        a7106_set_channel(app.rf.channel);    // 发送通道; RX -> STANDBY -> TX
        a7106_write_strobe(A7105_STROBE_STANDBY); // 发送前先设置为STANDBY;
        APP_USER_LOGI("A7105_STROBE_TX");
        return;
    } else {  // 可发送状态
        if (app.rf.reissue) {
            app.rf.reissue--;
            a7106_write_data(app.rf.buff, 4);  // RX -> STANDBY -> TX
            if (app.stop) {  // 停止
                app.stop = 0;
                memset(app.rf.buff, 0, 4);
            }
        }
    }
}
    
void exit_isr_callback(gpio_num_t gpio_num)
{
    app.rf.inter++;
}
//==============================================================================================================
//==============================================================================================================
#define KEY_RESET_FACTORY   0       // IO0
#define KEY_CLEAR_NETWORK   3       // IO3
static void key_scan_task(void)
{
    static uint8_t key_time = 0;
    static uint8_t key_value = 0;
    union8_t key_temp = { .value = 0 };
    key_temp.bits.bit0 = !gpio_get_level(KEY_RESET_FACTORY);
    key_temp.bits.bit1 = !gpio_get_level(KEY_CLEAR_NETWORK);
    //APP_USER_LOGI("KEY->key_temp = 0x%02x", key_temp.value);
    if (key_value && key_value == key_temp.value) { // 键值保持不变！
        if (++key_time == 80) {  // 5s
            if (key_temp.bits.bit0 == true) {  // IO0
                //esp_ota_reset_factory();  // 恢复到出厂固件
            } else if (key_temp.bits.bit1 == true) {   // IO21

            }
            APP_USER_LOGI("KEY->app.sys_reset = %d\r\n", key_value);
            app.sys_reset = true;  // 使能软复位
        }
    } else { // 键值发现了变化！
        if ((key_value && !key_temp.value) && (key_time > 1 && key_time < 10)) {  // 单击
            APP_USER_LOGI("KEY->Click = 0x%02x\r\n", key_value);
            if (key_value == 0x01) {  // IO0
                #if CONFIG_RS485RF_ENABLE
                hal_rs485_write((const uint8_t[]){0X52, 0X55, 0X99, 0X99, 0X99}, 5);
                #endif
                rf_motor_write((const uint8_t[]){0X55, 0X55, 0X99, 0X99}, 5);
            }
        }
        key_value = key_temp.value;
        key_time = 0;
    }
    return;
}

//=====================================================================================
//=====================================================================================
bool get_sys_config_network(void)  // LVGL显示用
{
    return false;  // 是否配网成功了
}

void esp_free_heap_print(void)
{
    #if 1  // debug
    APP_USER_LOGI("Free heap, current: %ld, minimum: %ld", 
                esp_get_free_heap_size(), 
                esp_get_minimum_free_heap_size());  // 打印内存
    APP_USER_LOGI("MALLOC_CAP_SPIRAM = %d, MALLOC_CAP_INTERNAL = %d", 
                heap_caps_get_free_size(MALLOC_CAP_SPIRAM), 
                heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
    #endif
}

void app_user_handle(void)
{
 
    key_scan_task();

    app_a7106_handler();

    /* 用户信息有更新 */
    if (nvs_user.update) {
        nvs_user.update = false;
        nvs_user_handle(&nvs_user, NVS_READWRITE);   // 写用户信息
        APP_USER_LOGI("nvs_user_handle = 0x%08lx", nvs_user.rfid.u32);
    }
    
    static uint8_t ledtime = 0;
    if (++ledtime > 5) {
        ledtime = 0;
        static bool led_blank = 0;
        led_blank = !led_blank;
        gpio_set_level(GPIO_NUM_37, led_blank);
    }
}


//=============================================================================================================== 
//=============================================================================================================== 
// 用户逻辑功能任务
static void app_user_task(void *arg)
{ 
	app.rf.match = 150;  // 15S对码
    while (520) {
        //=============================================================================
        // START... 
        //=============================================================================
        vTaskDelay(100);  /* 主任务执行的周期/MS */

        #if 1
        static uint8_t freetime = 0;
        if (++freetime > 200) {
            freetime = 0;
            esp_free_heap_print();  
        }
        #endif
 
        //=============================================================================
        app_user_handle();

        //========================================================================================
        // END...
    }
}

//=============================================================================================================== 
//=============================================================================================================== 


#if CONFIG_RS485RF_ENABLE
typedef struct {
    uint8_t addr;
    uint8_t data[4];
} rs485_tran_t;


void rs485_recv_callback(uart_port_t port, uint8_t *data, uint16_t len)
{
    APP_USER_LOGI("rs485_recv_callback[%d]: %.*s | %d", port, len, data, len);
    esp_log_buffer_hex("RS485", data, len);
    
#if 1
    if (len != sizeof(rs485_tran_t)) return;  // 数据长度不对
    rs485_tran_t *rs485 = (rs485_tran_t *)data;
    if (rs485->addr != nvs_user.addr) return;  // 地址不对！
    uint8_t reissue;
    if (rs485->data[0] == 0x55 && rs485->data[2] <= 0xAA) {  // 长按角度控制
        reissue = 6;   // 角度控制，需要连发
    } else {
        reissue = 1;   // 模式控制，只需一次
    }
    rf_motor_write(rs485->data, reissue);
    hal_rs485_write(data, len);  // 响应
#endif

    static bool led_blank = 0;
    led_blank = !led_blank;
    gpio_set_level(GPIO_NUM_36, led_blank);
}

void ble_gatts_recv_callback(uint8_t idx, uint8_t *data, uint8_t len)
{
    esp_log_buffer_hex("gatts", data, len);
    if (data[0] == 'A' && len == 3) {  // "addr"
        int addr = atoi((char *)&data[1]);
        APP_USER_LOGI("addr = %d", addr);
        nvs_user.addr = addr;
        nvs_user.update = true;
    }
}
#else
// TX: A5 FA 00 81 01 00 21 FB 
// RX: A5 FA 00 82 01 00 22 FB
typedef struct {
#define ASR_HEAD    0XA5
#define ASR_TAIL    0XFB
    uint8_t head[4];
    uint8_t vid;
    uint8_t res;
    uint8_t sum;
    uint8_t tail;
} uart_asr_t;  // 语音识别串口通信协议
 

typedef struct {
    uint8_t vid;
    uint8_t rf[4];
} rf_asr_t;

const rf_asr_t rf_asr_table[] = {
    {0x02, RF_MOTOR_MODE_SLEEP},
    {0x03, RF_MOTOR_MODE_ZERO},
    {0x04, RF_MOTOR_MODE_READ},
    {0x05, RF_MOTOR_MODE_CASUAL},
    {0x06, RF_MOTOR_MODE_TV},
    {0x07, RF_MOTOR_MODE_SNORE},

    {0x08, RF_MOTOR_NULL},
    {0x09, RF_MOTOR_BACK_UP},
    {0x0A, RF_MOTOR_BACK_DOWN},
    {0x0B, RF_MOTOR_LEG_UP},
    {0x0C, RF_MOTOR_LEG_DOWN},
    {0x0D, RF_MOTOR_ALL_UP},
    {0x0E, RF_MOTOR_ALL_DOWN},
};

#define RF_ASR_TABLE_SIZE    (sizeof(rf_asr_table) / sizeof(rf_asr_t))

void uart_recv_callback(uart_port_t port, uint8_t *data, uint16_t len)
{
    esp_log_buffer_hex("RS485", data, len);
    uart_asr_t *asr = (uart_asr_t *)data;
    if (asr->head[0] == ASR_HEAD && asr->tail == ASR_TAIL) {
        for (uint8_t i = 0; i < RF_ASR_TABLE_SIZE; i++) {
            if (asr->vid == rf_asr_table[i].vid) {
                APP_USER_LOGI("rf_asr_table[%d] = %d", i, asr->vid);
                
                uint8_t reissue;
                if (rf_asr_table[i].rf[0] == 0x55 && rf_asr_table[i].rf[2] <= 0xAA) {  // 长按角度控制
                    reissue = 100;   // 角度控制，需要连发
                } else {
                    reissue = 2;   // 模式控制，只需一次
                }
                if (asr->vid == 0x08) {  // STOP指令！
                    app.stop = 2;
                }
                rf_motor_write(rf_asr_table[i].rf, reissue);  // RF   
                break;
            }
        }
        static bool led_blank = 0;
        led_blank = !led_blank;
        gpio_set_level(GPIO_NUM_36, led_blank);
    }
}
#endif
//===================================================================================================================
//===================================================================================================================
// 奥格客户3套RS485设备
void app_user_init(void) 
{
    APP_USER_LOGI("app_user_init...");
    nvs_user_handle(&nvs_user, NVS_READONLY);   // 读用户信息
    APP_USER_LOGI("nvs_user.rfid = 0x%08lx", nvs_user.rfid.u32);
    APP_USER_LOGI("nvs_user.addr = %d", nvs_user.addr);

    hal_gpio_init();
#if CONFIG_RS485RF_ENABLE
    hal_rs485_init(rs485_recv_callback);
#else 
    hal_uart_init(uart_recv_callback);
#endif
    hal_a7106_init();
    hal_exti_init(exit_isr_callback);
    xTaskCreatePinnedToCore(app_user_task, "app_user", 4 * 1024, NULL, 5, NULL, APP_CPU_NUM);

#if CONFIG_RS485RF_ENABLE
    bluedroid_stack_init();
    ble_gatts_init();
    ble_gatts_register_callback(ble_gatts_recv_callback);
#endif
    /* END...................................................................................*/
}
/* END...................................................................................*/
// 查看错误码信息： https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/error-codes.html
// http://wiki.tjc1688.com/doku.php 
